package com.bjy.qa.util.fileexport;

import com.alibaba.fastjson.JSONObject;
import com.bjy.qa.entity.functionaltest.Api;
import com.bjy.qa.entity.functionaltest.ApiParam;
import com.bjy.qa.enumtype.ParamKind;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Random;

public class LocustExport {
    private static String charset = "UTF-8"; // 默认参数字符集

    StringBuffer testScript = new StringBuffer();

    /**
     * 将 Api 格式转为 Locust 文本
     *
     * @param api api
     * @return
     */
    public String toLocust(Api api) {
        this.exportHead();
        this.exportHost(api.getHost());

        switch (api.getMethod().toUpperCase()) {
            case "GET":
                this.exportGet(api);
                break;
            case "POST":
                this.exportPost(api);
                break;
            case "PUT":
//                this.exportPut(api);
//                break;
            case "DELETE":
//                this.exportDelete(api);
//                break;
            case "BINARY":
//                this.exportBinary(api);
//                break;
            default:
                testScript.append(String.format("===>>  Locust 脚本导出失败，暂不支持的 HTTP Method: %s  <<===", api.getMethod()));
                break;
        }

        return testScript.toString();
    }

    /**
     * 导出 header 部分
     * @return
     */
    private boolean exportHead() {
        testScript.append("#coding=utf-8\n" +
                "from deepdiff import DeepDiff\n" +
                "import urllib3\n" +
                "import json\n" +
                "from locust import HttpUser, between, task\n" +
                "\n" +
                "class utils():\n" +
                "    @staticmethod\n" +
                "    def diffJson(assert_data, response_data):\n" +
                "        temp = DeepDiff(assert_data, response_data) # 比较两个 json 的差异\n" +
                "        if \"dictionary_item_added\" in temp:\n" +
                "            temp.pop(\"dictionary_item_added\") # 去掉 response 比 assert 多出的 key 的错误\n" +
                "        return temp\n\n" +
                "class MyHttpUser(HttpUser):\n" +
                "    urllib3.disable_warnings() # 关闭 http 警告\n" +
                "    wait_time = between(0.1, 1)\n");
        return true;
    }

    /**
     * 导出 hsot
     * @param host host
     * @return
     */
    private boolean exportHost(String host) {
        testScript.append(String.format("    host = '%s'\n\n", host));
        return true;
    }

    /**
     * 返回 url
     * @param api api
     * @return
     */
    private String getUri(Api api) {
        return api.getUri();
    }

    /**
     * 返回接口名称
     * @param api api
     * @return
     */
    private String getApiName(Api api) {
        return api.getName();
    }

    /**
     * 返回 url 链接参数
     * @param api api
     * @return
     */
    private String getUrlParam(Api api) {
        for (ApiParam apiParam : api.getApiParams()) {
            if (apiParam.getKind() == ParamKind.KIND_URL_PARAM) {
                JSONObject jsonObject = JSONObject.parseObject(apiParam.getExample());
                StringBuffer stringBuffer = new StringBuffer();
                jsonObject.keySet().forEach(key -> {
                    if (stringBuffer.length() > 0) {
                        stringBuffer.append("&");
                    }

                    Object value = jsonObject.get(key);
                    if (value instanceof String) {
                        try {
                            stringBuffer.append(key + "=" + URLEncoder.encode(value.toString(), charset));
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                            throw new RuntimeException(e);
                        }
                    } else {
                        stringBuffer.append(key + "=" + value);
                    }
                });
                if (stringBuffer.length() != 0) {
                    stringBuffer.insert(0, "?");
                }

                return stringBuffer.toString();
            }
        }
        return "";
    }

    /**
     * 返回 header
     * @param api api
     * @param uniqueName 参数唯一值
     * @return
     */
    private String getHeader(Api api, String uniqueName) {
        for (ApiParam apiParam : api.getApiParams()) {
            if (apiParam.getKind() == ParamKind.KIND_HEADER) {
                String headersExample = apiParam.getExample();
                if (headersExample.equals("{}")) {
                    return "";
                } else {
                    try {
                        ObjectMapper mapper = new ObjectMapper();
                        Object jsonObj = mapper.readValue(headersExample, Object.class);
                        headersExample = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObj); // json 格式化
                    } catch (Exception e) {
                        e.printStackTrace();
                        return "";
                    }
                    headersExample = headersExample.replace("\n", "\n        ");

                    StringBuffer headers = new StringBuffer();
                    headers.append(String.format("        header_%s = %s\n", uniqueName, headersExample));
                    headers.append(String.format("        self.client.headers.update(header_%s)\n\n", uniqueName));
                    return headers.toString();
                }
            }
        }
        return "";
    }

    /**
     * 返回 body 变量数据。例如：body_data_12345 = { "a" : "x" }
     * @param api api
     * @param uniqueName 参数唯一值
     * @return
     */
    private String getBodyData(Api api, String uniqueName) {
        for (ApiParam apiParam : api.getApiParams()) {
            if (apiParam.getKind() == ParamKind.KIND_BODY) {
                String bodyExample = apiParam.getExample();
                try {
                    ObjectMapper mapper = new ObjectMapper();
                    Object jsonObj = mapper.readValue(bodyExample, Object.class);
                    bodyExample = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObj); // json 格式化
                } catch (Exception e) {
                    e.printStackTrace();
                    return "";
                }

                bodyExample = bodyExample.replace("\n", "\n        ");
                return String.format("        body_data_%s = %s\n", uniqueName, bodyExample);
            }
        }
        return "";
    }

    /**
     * 返回 body 参数名。例如：json=body_data_12345
     * @param api api
     * @param uniqueName 参数唯一值
     * @return
     */
    private String getBodyParam(Api api, String uniqueName) {
        if ("FORM".equalsIgnoreCase(api.getExtra1())) {
            return String.format(" data=body_data_%s,", uniqueName);
        } else {
            return String.format(" json=body_data_%s,", uniqueName);
        }
    }

    /**
     * 返回 断言 变量数据。例如：assert_data_12345 = { "code" : 0 }
     * @param api api
     * @param uniqueName 参数唯一值
     * @return
     */
    private String getAssertData(Api api, String uniqueName) {
        for (ApiParam apiParam : api.getApiParams()) {
            if (apiParam.getKind() == ParamKind.KIND_ASSERT) {
                String bodyExample = apiParam.getExample();
                try {
                    ObjectMapper mapper = new ObjectMapper();
                    Object jsonObj = mapper.readValue(bodyExample, Object.class);
                    bodyExample = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObj); // json 格式化
                } catch (Exception e) {
                    e.printStackTrace();
                    return "";
                }

                bodyExample = bodyExample.replace("\n", "\n        ");
                return String.format("        assert_data_%s = %s\n\n", uniqueName, bodyExample);
            }
        }
        return "";
    }

    /**
     * 导出 http - get 协议
     * @param api api
     * @return
     */
    private boolean exportGet(Api api) {
        String uniqueName = this.uniqueValue();

        testScript.append("    @task\n");
        testScript.append(String.format("    def task_%s(self):\n", uniqueName));
        testScript.append(this.getBodyData(api, uniqueName));
        testScript.append(this.getAssertData(api, uniqueName));
        testScript.append(this.getHeader(api, uniqueName));
        testScript.append(String.format("        # %s\n", this.getApiName(api)));
        testScript.append(String.format("        with self.client.get(\"%s%s\",%s catch_response=True, verify=False) as response:\n", this.getUri(api), this.getUrlParam(api), this.getBodyParam(api, uniqueName)));
        testScript.append(String.format("            diff = utils.diffJson(assert_data_%s, json.loads(response.text))\n", uniqueName));
        testScript.append("            if not diff:\n" +
                "                response.success()\n" +
                "            else:\n");
        testScript.append(String.format("                response.failure(\"请求 %s 校验失败:\" + json.dumps(diff))", this.getApiName(api)));
        return true;
    }

    /**
     * 导出 http - post 协议
     * @param api api
     * @return
     */
    private boolean exportPost(Api api) {
        String uniqueName = this.uniqueValue();

        testScript.append("    @task\n");
        testScript.append(String.format("    def task_%s(self):\n", uniqueName));
        testScript.append(this.getBodyData(api, uniqueName));
        testScript.append(this.getAssertData(api, uniqueName));
        testScript.append(this.getHeader(api, uniqueName));
        testScript.append(String.format("        # %s\n", this.getApiName(api)));
        testScript.append(String.format("        with self.client.post(\"%s%s\",%s catch_response=True, verify=False) as response:\n", this.getUri(api), this.getUrlParam(api), this.getBodyParam(api, uniqueName)));
        testScript.append(String.format("            diff = utils.diffJson(assert_data_%s, json.loads(response.text))\n", uniqueName));
        testScript.append("            if not diff:\n" +
                "                response.success()\n" +
                "            else:\n");
        testScript.append(String.format("                response.failure(\"请求 %s 校验失败:\" + json.dumps(diff))", this.getApiName(api)));
        return true;
    }

    /**
     * 导出 http - put 协议
     * @param api
     * @return
     */
    private boolean exportPut(Api api) {
        return true;
    }

    /**
     * 导出 http - delete 协议
     * @param api
     * @return
     */
    private boolean exportDelete(Api api) {
        return true;
    }

    /**
     * 导出 http - binary 协议
     * @param api
     * @return
     */
    private boolean exportBinary(Api api) {
        return true;
    }

    /**
     * 5 位唯一值
     * @return
     */
    private String uniqueValue() {
        Random random = new Random();
        Long uniqueValue = System.currentTimeMillis() + Long.valueOf(random.nextInt(100));
        return String.valueOf(uniqueValue).substring(String.valueOf(uniqueValue).length() - 5);
    }
}
